| Conditions | 37 | 
| Total Lines | 442 | 
| Code Lines | 293 | 
| Lines | 0 | 
| Ratio | 0 % | 
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like script.js ➔ createMap often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | /* | ||
| 70 | function createMap(mapOpts, poi) { | ||
| 71 | |||
| 72 | // const mapOpts = olMapData[0].mapOpts; | ||
| 73 | // const poi = olMapData[0].poi; | ||
| 74 | |||
| 75 |     if (!olEnable) { | ||
| 76 | return null; | ||
| 77 | } | ||
| 78 |     if (!olTestCSSsupport()) { | ||
| 79 | olEnable = false; | ||
| 80 | return null; | ||
| 81 | } | ||
| 82 | |||
| 83 | // find map element location | ||
| 84 | const cleartag = document.getElementById(mapOpts.id + '-clearer'); | ||
| 85 |     if (cleartag === null) { | ||
| 86 | return null; | ||
| 87 | } | ||
| 88 | // create map element and add to document | ||
| 89 | const fragment = olCreateMaptag(mapOpts.id, mapOpts.width, mapOpts.height); | ||
| 90 | cleartag.parentNode.insertBefore(fragment, cleartag); | ||
| 91 | |||
| 92 | /** dynamic map extent. */ | ||
| 93 | let extent = ol.extent.createEmpty(); | ||
| 94 |     let overlayGroup = new ol.layer.Group({title: 'Overlays', fold: 'open', layers: []}); | ||
| 95 |     const baseLyrGroup = new ol.layer.Group({'title': 'Base maps', layers: []}); | ||
| 96 | |||
| 97 |     const map = new ol.Map({ | ||
| 98 | target: document.getElementById(mapOpts.id), | ||
| 99 | layers: [baseLyrGroup, overlayGroup], | ||
| 100 |         view:     new ol.View({ | ||
| 101 | center: ol.proj.transform([mapOpts.lon, mapOpts.lat], 'EPSG:4326', 'EPSG:3857'), | ||
| 102 | zoom: mapOpts.zoom, | ||
| 103 | projection: 'EPSG:3857' | ||
| 104 | }), | ||
| 105 | controls: [ | ||
| 106 |             new ol.control.Attribution({ | ||
| 107 | collapsible: true, | ||
| 108 | collapsed: true | ||
| 109 | }) | ||
| 110 | ] | ||
| 111 | }); | ||
| 112 | |||
| 113 |     if (osmEnable) { | ||
| 114 | baseLyrGroup.getLayers().push( | ||
| 115 |             new ol.layer.Tile({ | ||
| 116 | visible: true, | ||
| 117 | title: 'OSM', | ||
| 118 | type: 'base', | ||
| 119 | source: new ol.source.OSM() | ||
| 120 | })); | ||
| 121 | |||
| 122 | baseLyrGroup.getLayers().push( | ||
| 123 |             new ol.layer.Tile({ | ||
| 124 | visible: mapOpts.baselyr === "cycle map", | ||
| 125 | title: 'cycle map', | ||
| 126 | type: 'base', | ||
| 127 |                 source:  new ol.source.OSM({ | ||
| 128 |                     url:          'https://{a-c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=' + tfApiKey, | ||
| 129 | attributions: 'Data ©ODbL <a href="https://openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>, ' | ||
| 130 | + 'Tiles ©<a href="https://www.thunderforest.com/" target="_blank">Thunderforest</a>' | ||
| 131 | + '<img src="https://www.thunderforest.com/favicon.ico" alt="Thunderforest logo"/>' | ||
| 132 | }) | ||
| 133 | })); | ||
| 134 | |||
| 135 | baseLyrGroup.getLayers().push( | ||
| 136 |             new ol.layer.Tile({ | ||
| 137 | visible: mapOpts.baselyr === "transport", | ||
| 138 | title: 'transport', | ||
| 139 | type: 'base', | ||
| 140 |                 source:  new ol.source.OSM({ | ||
| 141 |                     url:          'https://{a-c}.tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey=' + tfApiKey, | ||
| 142 | attributions: 'Data ©ODbL <a href="https://openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>, ' | ||
| 143 | + 'Tiles ©<a href="https://www.thunderforest.com/" target="_blank">Thunderforest</a>' | ||
| 144 | + '<img src="https://www.thunderforest.com/favicon.ico" alt="Thunderforest logo"/>' | ||
| 145 | }) | ||
| 146 | })); | ||
| 147 | |||
| 148 | baseLyrGroup.getLayers().push( | ||
| 149 |             new ol.layer.Tile({ | ||
| 150 | visible: mapOpts.baselyr === "landscape", | ||
| 151 | title: 'landscape', | ||
| 152 | type: 'base', | ||
| 153 |                 source:  new ol.source.OSM({ | ||
| 154 |                     url:          'https://{a-c}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png?apikey=' + tfApiKey, | ||
| 155 | attributions: 'Data ©ODbL <a href="https://openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>, ' | ||
| 156 | + 'Tiles ©<a href="https://www.thunderforest.com/" target="_blank">Thunderforest</a>' | ||
| 157 | + '<img src="https://www.thunderforest.com/favicon.ico" alt="Thunderforest logo"/>' | ||
| 158 | }) | ||
| 159 | })); | ||
| 160 | |||
| 161 | baseLyrGroup.getLayers().push( | ||
| 162 |             new ol.layer.Tile({ | ||
| 163 | visible: mapOpts.baselyr === "outdoors", | ||
| 164 | title: 'outdoors', | ||
| 165 | type: 'base', | ||
| 166 |                 source:  new ol.source.OSM({ | ||
| 167 |                     url:          'https://{a-c}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=' + tfApiKey, | ||
| 168 | attributions: 'Data ©ODbL <a href="https://openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>, ' | ||
| 169 | + 'Tiles ©<a href="https://www.thunderforest.com/" target="_blank">Thunderforest</a>' | ||
| 170 | + '<img src="https://www.thunderforest.com/favicon.ico" alt="Thunderforest logo"/>' | ||
| 171 | }) | ||
| 172 | })); | ||
| 173 | } | ||
| 174 | |||
| 175 |     if (bEnable && bApiKey !== '') { | ||
| 176 | baseLyrGroup.getLayers().push( | ||
| 177 |             new ol.layer.Tile({ | ||
| 178 | visible: mapOpts.baselyr === "bing road", | ||
| 179 | title: 'bing road', | ||
| 180 | type: 'base', | ||
| 181 |                 source:  new ol.source.BingMaps({ | ||
| 182 | key: bApiKey, | ||
| 183 | imagerySet: 'Road' | ||
| 184 | }) | ||
| 185 | })); | ||
| 186 | |||
| 187 | baseLyrGroup.getLayers().push( | ||
| 188 |             new ol.layer.Tile({ | ||
| 189 | visible: mapOpts.baselyr === "bing sat", | ||
| 190 | title: 'bing sat', | ||
| 191 | type: 'base', | ||
| 192 |                 source:  new ol.source.BingMaps({ | ||
| 193 | key: bApiKey, | ||
| 194 | imagerySet: 'Aerial' | ||
| 195 | }) | ||
| 196 | })); | ||
| 197 | |||
| 198 | baseLyrGroup.getLayers().push( | ||
| 199 |             new ol.layer.Tile({ | ||
| 200 | visible: mapOpts.baselyr === "bing hybrid", | ||
| 201 | title: 'bing hybrid', | ||
| 202 | type: 'base', | ||
| 203 |                 source:  new ol.source.BingMaps({ | ||
| 204 | key: bApiKey, | ||
| 205 | imagerySet: 'AerialWithLabels' | ||
| 206 | }) | ||
| 207 | })); | ||
| 208 | } | ||
| 209 | |||
| 210 |     if (stamenEnable) { | ||
| 211 | baseLyrGroup.getLayers().push( | ||
| 212 |             new ol.layer.Tile({ | ||
| 213 | visible: mapOpts.baselyr === "toner", | ||
| 214 | type: 'base', | ||
| 215 | title: 'toner', | ||
| 216 |                 source:  new ol.source.Stamen({layer: 'toner'}) | ||
| 217 | }) | ||
| 218 | ); | ||
| 219 | |||
| 220 | baseLyrGroup.getLayers().push( | ||
| 221 |             new ol.layer.Tile({ | ||
| 222 | visible: mapOpts.baselyr === "terrain", | ||
| 223 | type: 'base', | ||
| 224 | title: 'terrain', | ||
| 225 |                 source:  new ol.source.Stamen({layer: 'terrain'}) | ||
| 226 | }) | ||
| 227 | ); | ||
| 228 | } | ||
| 229 | |||
| 230 | extent = ol.extent.extend(extent, map.getView().calculateExtent()); | ||
| 231 | |||
| 232 | const iconScale = 1.0; | ||
| 233 | const vectorSource = new ol.source.Vector(); | ||
| 234 |     poi.forEach((p) => { | ||
| 235 |         const f = new ol.Feature({ | ||
| 236 | geometry: new ol.geom.Point(ol.proj.fromLonLat([p.lon, p.lat])), | ||
| 237 | description: p.txt, | ||
| 238 | img: p.img, | ||
| 239 | rowId: p.rowId, | ||
| 240 | lat: p.lat, | ||
| 241 | lon: p.lon, | ||
| 242 | angle: p.angle, | ||
| 243 | opacity: p.opacity, | ||
| 244 |             alt:         p.img.substring(0, p.img.lastIndexOf(".")) | ||
| 245 | }); | ||
| 246 | f.setId(p.rowId); | ||
| 247 | vectorSource.addFeature(f); | ||
| 248 | }); | ||
| 249 | |||
| 250 |     const vectorLayer = new ol.layer.Vector({ | ||
| 251 | title: 'POI', | ||
| 252 | visible: true, | ||
| 253 | source: vectorSource, | ||
| 254 |         style(feature, resolution) { | ||
| 255 |             const img = feature.get('img'); | ||
| 256 |             const opacity = feature.get('opacity'); | ||
| 257 |             const angle = feature.get('angle'); | ||
| 258 |             const text = feature.get('rowId'); | ||
| 259 | |||
| 260 |             return new ol.style.Style({ | ||
| 261 |                 image: new ol.style.Icon({ | ||
| 262 |                     src:         `${DOKU_BASE}lib/plugins/openlayersmap/icons/${img}`, | ||
| 263 | crossOrigin: '', | ||
| 264 | opacity: opacity, | ||
| 265 | scale: iconScale, | ||
| 266 | rotation: angle * Math.PI / 180, | ||
| 267 | }), | ||
| 268 |                 text:  new ol.style.Text({ | ||
| 269 |                     text:           `${text}`, | ||
| 270 | textAlign: 'center', | ||
| 271 | textBaseline: 'middle', | ||
| 272 | offsetX: (8 + 4) * iconScale, | ||
| 273 | offsetY: -8 * iconScale, | ||
| 274 | scale: iconScale, | ||
| 275 |                     fill:           new ol.style.Fill({color: 'rgb(0,0,0)'}), | ||
| 276 | font: 'bold 1em monospace', | ||
| 277 |                     backgroundFill: new ol.style.Fill({color: 'rgba(255,255,255,.4)'}) | ||
| 278 | }) | ||
| 279 | }); | ||
| 280 | } | ||
| 281 | }); | ||
| 282 | overlayGroup.getLayers().push(vectorLayer); | ||
| 283 |     if (mapOpts.autozoom) { | ||
| 284 | extent = ol.extent.extend(extent, vectorSource.getExtent()); | ||
| 285 | map.getView().fit(extent); | ||
| 286 | } | ||
| 287 | |||
| 288 |     if (mapOpts.controls === 1) { | ||
| 289 | map.addControl(new ol.control.Zoom()); | ||
| 290 |         map.addControl(new ol.control.ScaleLine({bar: true, text: true})); | ||
| 291 |         map.addControl(new ol.control.MousePosition({ | ||
| 292 | coordinateFormat: ol.coordinate.createStringXY(4), projection: 'EPSG:4326', | ||
| 293 | })); | ||
| 294 |         map.addControl(new ol.control.FullScreen({ | ||
| 295 | label: '✈' | ||
| 296 | })); | ||
| 297 |         map.addControl(new ol.control.OverviewMap({ | ||
| 298 | label: '+', | ||
| 299 |             layers: [new ol.layer.Tile({ | ||
| 300 | source: new ol.source.OSM() | ||
| 301 | })] | ||
| 302 | })); | ||
| 303 |         map.addControl(new ol.control.LayerSwitcher({ | ||
| 304 | activationMode: 'click', | ||
| 305 | label: '\u2630', | ||
| 306 | collapseLabel: '\u00BB', | ||
| 307 | })); | ||
| 308 | } | ||
| 309 | |||
| 310 |     if (mapOpts.kmlfile.length > 0) { | ||
| 311 |         try { | ||
| 312 |             const kmlSource = new ol.source.Vector({ | ||
| 313 | url: DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.kmlfile, | ||
| 314 | format: new ol.format.KML(), | ||
| 315 | }); | ||
| 316 |             overlayGroup.getLayers().push(new ol.layer.Vector({title: 'KML file', visible: true, source: kmlSource})); | ||
| 317 | |||
| 318 |             if (mapOpts.autozoom) { | ||
| 319 |                 kmlSource.once('change', function () { | ||
| 320 | extent = ol.extent.extend(extent, kmlSource.getExtent()); | ||
| 321 | map.getView().fit(extent); | ||
| 322 | }); | ||
| 323 | } | ||
| 324 |         } catch (e) { | ||
| 325 | console.error(e); | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 |     if (mapOpts.geojsonfile.length > 0) { | ||
| 330 |         try { | ||
| 331 | // these are the same colour as in StaticMap#drawJSON() | ||
| 332 |             const geoJsonStyle = { | ||
| 333 |                 'Point':           new ol.style.Style({ | ||
| 334 |                     image: new ol.style.Circle({ | ||
| 335 |                         fill:   new ol.style.Fill({ | ||
| 336 | color: 'rgba(255,0,255,0.4)', | ||
| 337 | }), | ||
| 338 | radius: 5, | ||
| 339 |                         stroke: new ol.style.Stroke({ | ||
| 340 | color: 'rgba(255,0,255,0.9)', | ||
| 341 | width: 1, | ||
| 342 | }), | ||
| 343 | }), | ||
| 344 | }), | ||
| 345 |                 'LineString':      new ol.style.Style({ | ||
| 346 |                     stroke: new ol.style.Stroke({ | ||
| 347 | color: 'rgba(255,0,255,0.9)', | ||
| 348 | width: 3, | ||
| 349 | }), | ||
| 350 | }), | ||
| 351 |                 'MultiLineString': new ol.style.Style({ | ||
| 352 |                     stroke: new ol.style.Stroke({ | ||
| 353 | color: 'rgba(255,0,255,0.9)', | ||
| 354 | width: 3, | ||
| 355 | }), | ||
| 356 | }), | ||
| 357 |                 'Polygon':         new ol.style.Style({ | ||
| 358 |                     stroke: new ol.style.Stroke({ | ||
| 359 | color: 'rgba(255,0,255,0.9)', | ||
| 360 | width: 3, | ||
| 361 | }), | ||
| 362 |                     fill:   new ol.style.Fill({ | ||
| 363 | color: 'rgba(255,0,255,0.4)', | ||
| 364 | }), | ||
| 365 | }), | ||
| 366 |                 'MultiPolygon':    new ol.style.Style({ | ||
| 367 |                     stroke: new ol.style.Stroke({ | ||
| 368 | color: 'rgba(255,0,255,0.9)', | ||
| 369 | width: 3, | ||
| 370 | }), | ||
| 371 |                     fill:   new ol.style.Fill({ | ||
| 372 | color: 'rgba(255,0,255,0.4)', | ||
| 373 | }), | ||
| 374 | }), | ||
| 375 | }; | ||
| 376 |             const geoJsonSource = new ol.source.Vector({ | ||
| 377 | url: DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.geojsonfile, | ||
| 378 | format: new ol.format.GeoJSON(), | ||
| 379 | }); | ||
| 380 |             overlayGroup.getLayers().push(new ol.layer.Vector({ | ||
| 381 | title: 'GeoJSON file', visible: true, source: geoJsonSource, | ||
| 382 |                 style: function (feature) { | ||
| 383 | return geoJsonStyle[feature.getGeometry().getType()]; | ||
| 384 | }, | ||
| 385 | })); | ||
| 386 | |||
| 387 |             if (mapOpts.autozoom) { | ||
| 388 |                 geoJsonSource.once('change', function () { | ||
| 389 | extent = ol.extent.extend(extent, geoJsonSource.getExtent()); | ||
| 390 | map.getView().fit(extent); | ||
| 391 | }); | ||
| 392 | } | ||
| 393 |         } catch (e) { | ||
| 394 | console.error(e); | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 398 |     if (mapOpts.gpxfile.length > 0) { | ||
| 399 |         try { | ||
| 400 | // these are the same colour as in StaticMap#drawGPX() | ||
| 401 |             const gpxJsonStyle = { | ||
| 402 |                 'Point':           new ol.style.Style({ | ||
| 403 |                     image: new ol.style.Circle({ | ||
| 404 |                         fill:   new ol.style.Fill({ | ||
| 405 | color: 'rgba(0,0,255,0.4)', | ||
| 406 | }), | ||
| 407 | radius: 5, | ||
| 408 |                         stroke: new ol.style.Stroke({ | ||
| 409 | color: 'rgba(0,0,255,0.9)', | ||
| 410 | width: 1, | ||
| 411 | }), | ||
| 412 | }), | ||
| 413 | }), | ||
| 414 |                 'LineString':      new ol.style.Style({ | ||
| 415 |                     stroke: new ol.style.Stroke({ | ||
| 416 | color: 'rgba(0,0,255,0.9)', | ||
| 417 | width: 3, | ||
| 418 | }), | ||
| 419 | }), | ||
| 420 |                 'MultiLineString': new ol.style.Style({ | ||
| 421 |                     stroke: new ol.style.Stroke({ | ||
| 422 | color: 'rgba(0,0,255,0.9)', | ||
| 423 | width: 3, | ||
| 424 | }), | ||
| 425 | }), | ||
| 426 | }; | ||
| 427 |             const gpxSource = new ol.source.Vector({ | ||
| 428 | url: DOKU_BASE + "lib/exe/fetch.php?media=" + mapOpts.gpxfile, | ||
| 429 | format: new ol.format.GPX(), | ||
| 430 | }); | ||
| 431 |             overlayGroup.getLayers().push(new ol.layer.Vector({ | ||
| 432 | title: 'GPS track', visible: true, source: gpxSource, | ||
| 433 |                 style: function (feature) { | ||
| 434 | return gpxJsonStyle[feature.getGeometry().getType()]; | ||
| 435 | }, | ||
| 436 | })); | ||
| 437 | |||
| 438 |             if (mapOpts.autozoom) { | ||
| 439 |                 gpxSource.once('change', function () { | ||
| 440 | extent = ol.extent.extend(extent, gpxSource.getExtent()); | ||
| 441 | map.getView().fit(extent); | ||
| 442 | }); | ||
| 443 | } | ||
| 444 |         } catch (e) { | ||
| 445 | console.error(e); | ||
| 446 | } | ||
| 447 | } | ||
| 448 | |||
| 449 |     const container = document.getElementById('popup'); | ||
| 450 |     const content = document.getElementById('popup-content'); | ||
| 451 |     const closer = document.getElementById('popup-closer'); | ||
| 452 | |||
| 453 |     const overlay = new ol.Overlay({ | ||
| 454 | element: container, | ||
| 455 | positioning: 'center-center', | ||
| 456 | stopEvent: true, | ||
| 457 |         autoPan:     { | ||
| 458 |             animation: { | ||
| 459 | duration: 250, | ||
| 460 | } | ||
| 461 | }, | ||
| 462 | }); | ||
| 463 | map.addOverlay(overlay); | ||
| 464 | |||
| 465 | /** | ||
| 466 | * Add a click handler to hide the popup. | ||
| 467 |      * @return {boolean} Don't follow the href. | ||
| 468 | */ | ||
| 469 |     closer.onclick = function () { | ||
| 470 | overlay.setPosition(undefined); | ||
| 471 | closer.blur(); | ||
| 472 | return false; | ||
| 473 | }; | ||
| 474 | |||
| 475 | // display popup on click | ||
| 476 |     map.on('singleclick', function (evt) { | ||
| 477 |         const selFeature = map.forEachFeatureAtPixel(evt.pixel, function (feature) { | ||
| 478 | return feature; | ||
| 479 | }); | ||
| 480 |         if (selFeature) { | ||
| 481 | overlay.setPosition(evt.coordinate); | ||
| 482 | |||
| 483 | let pContent = '<div class="spacer"> </div>'; | ||
| 484 | // let locDesc = ''; | ||
| 485 | |||
| 486 |             if (selFeature.get('rowId') !== undefined) { | ||
| 487 |                 pContent += '<span class="rowId">' + selFeature.get('rowId') + ': </span>'; | ||
| 488 | } | ||
| 489 |             if (selFeature.get('name') !== undefined) { | ||
| 490 |                 pContent += '<span class="txt">' + selFeature.get('name') + '</span>'; | ||
| 491 |                 // locDesc = selFeature.get('name'); | ||
| 492 | // TODO strip <p> tag from locDesc | ||
| 493 |                 // locDesc = selFeature.get('name').split(/\s+/).slice(0,2).join('+'); | ||
| 494 | } | ||
| 495 |             if (selFeature.get('ele') !== undefined) { | ||
| 496 |                 pContent += '<div class="ele">elevation: ' + selFeature.get('ele') + '</div>'; | ||
| 497 | } | ||
| 498 |             if (selFeature.get('type') !== undefined) { | ||
| 499 |                 pContent += '<div>' + selFeature.get('type') + '</div>'; | ||
| 500 | } | ||
| 501 |             if (selFeature.get('time') !== undefined) { | ||
| 502 |                 pContent += '<div class="time">time: ' + selFeature.get('time') + '</div>'; | ||
| 503 | } | ||
| 504 |             if (selFeature.get('description') !== undefined) { | ||
| 505 |                 pContent += '<div class="desc">' + selFeature.get('description') + '</div>'; | ||
| 506 | } | ||
| 507 |             if (selFeature.get('img') !== undefined) { | ||
| 508 |                 const _alt = selFeature.get('alt'); | ||
| 509 | pContent += '<div class="coord" title="lat;lon">' + | ||
| 510 |                     '<img alt="' + _alt + '" src="' + DOKU_BASE + 'lib/plugins/openlayersmap/icons/' + selFeature.get('img') + | ||
| 511 |                     '" width="16" height="16" ' + 'style="transform:rotate(' + selFeature.get('angle') + 'deg)" /> ' + | ||
| 512 |                     '<a href="geo:' + selFeature.get('lat') + ',' + selFeature.get('lon') + '?q=' + selFeature.get('lat') + | ||
| 754 |